#include <iostream>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

#include <cstdio>
#include <cstring>
#include <cassert>
using namespace std;

// 父进程进程进行写入，父进程进行读取
int main()
{
    // 1.创建管道文件，打开读写端
    int fds[2];
    int n = pipe(fds);
    assert(n == 0);

    // 2.fork创建子进程
    pid_t id = fork();
    assert(id >= 0);
    if (id == 0)
    {
        // 子进程进行写入
        close(fds[0]);
        // 子进程通信代码
        const char *s = "我是子进程，我正在给你发消息";
        int cnt = 10;
        while (cnt--)
        {
            char buffer[1024];
            snprintf(buffer, sizeof buffer, "child -> parent say: %s[%d][%d]", s, cnt, getpid());
            // 如果写方写满了，读端没有读取，写端就会阻塞，等待对方读取
            write(fds[1], buffer, strlen(buffer));
            cout << "count:" << cnt << endl;
            sleep(1); // 每隔一秒写一次
            // break;
        }

        // 子进程关闭写端
        close(fds[1]);
        cout << "子进程关闭自己的写端" << endl;
        exit(0);
    }
    // 父进程进行读取，关闭写
    close(fds[1]);

    // 父进程通信代码
    while (true)
    {
        char *buffer[1024];
        // 如果读端没有数据，读端在读，默认会阻塞等待当前正在读取的进程
        ssize_t s = read(fds[0], buffer, sizeof(buffer) - 1); //-1 可以保证不会读取超过1023给个数据

        if (s > 0)
        {
            buffer[s] = '\0';
            cout << "Get message# " << (char *)buffer << "| my pid: " << getpid() << endl;
        }
        else if (s == 0)
        {
            // 读到文件结尾
            cout << "read:" << s << endl;
            break;
        }
        // 父进程没有进行sleep
    }

    // 4 父亲关闭读端，写进程没有意义！
    close(fds[0]);
    cout << "父进程关闭读端" << endl;

    int status = 0;
    n = waitpid(id, &status, 0);
    int exitcode = (status >> 8) & 0xff;
    int exitsignal = status & 0x7f;
    cout << "子进程退出码:" << exitcode << " 子进程退出信号:" << exitsignal << endl;
    assert(n == id);
    return 0;
}